<?php

namespace app\api\controller;

use app\admin\model\Transaction;
use app\admin\model\user\Balance;
use app\admin\model\user\Extend;
use app\common\controller\Api;
use app\common\library\Reserve as ReserveLib;
use app\common\library\Pay as PayLib;
use app\common\library\Credit as CreditLib;

use app\common\library\Tongtongsuo;
use app\common\library\Yunding;
use app\common\model\RechargeSetting;
use app\common\model\Third;
use Carbon\Carbon;
use EasyWeChat\Factory;
use think\Env;
use think\Log;
use think\Db;

class Payment extends Api
{
    protected $noNeedLogin = ['notice'];
    protected $noNeedRight = ['*'];



    public function createTransaction($passType = null, $passReserveInfo = null)
    {
        $user = $this->auth->getUser();

        // 把微信支付证书cert和key放到文件里

        $certFile = APP_PATH . '/cert/apiclient_cert.pem';
        $keyFile = APP_PATH . '/cert/apiclient_key.pem';

        $appId = Env::get('mp.appid');
        $payMerchantId = Env::get('mp.pay_merchant_id');
        $payApiKey = Env::get('mp.pay_api_key');

        $testPay = Env::get('common.test_pay');
        $type = $this->request->post('type', 'other');

        $fee = 0;
        $extraInfo = '';
        if (Transaction::TRANS_TYPE_RECHARGE == $type) {
            $itemKey = $this->request->post('item_key');
            $recharge = RechargeSetting::get($itemKey);
            if (1 == $recharge->only_one) { // 设置为只能充一次，判断是否已经使用过
                $result = Transaction::where('user_id', $user->id)
                    ->where('type', Transaction::TRANS_TYPE_RECHARGE)
                    ->where('extra_info', $itemKey)
                    ->where('status', 2) // 支付成功
                    ->count();

                if ($result > 0) {
                    $this->error('此充值类型为只能享受一次，不能重复使用');
                }
            }
            $fee = $recharge->num;
            $extraInfo = $recharge->id;

        } else if (Transaction::TRANS_TYPE_BUY_CARD == $type) {
            $itemKey = $this->request->post('item_key');
            $card = \app\common\model\Card::get($itemKey);

            //判断是否超过了此卡的购买次数限制
            if ($card->could_buy_number) {
                $alreadyCouldNumber = \app\admin\model\user\Card::where('user_id', $user->id)
                    ->where('card_id', $card->id)
                    ->count();

                if ($alreadyCouldNumber >= $card->could_buy_number) {
                    $this->error("对不起，此卡有购买次数限制，你已经购买过${alreadyCouldNumber}次");
                }
            }

            $fee = $card->card_price;
            $extraInfo = $card->id;

        } else if (Transaction::TRANS_TYPE_DIRECT_BUY == $type ) {

            $reserveInfo = $this->request->post('reserve_info/a');

            $fee = $reserveInfo['price'];
            $extraInfo = json_encode($reserveInfo);
        } else {
          if (Transaction::TRANS_TYPE_DIRECT_BUY == $passType
          || Transaction::TRANS_TYPE_PUNISH == $passType
          || Transaction::TRANS_TYPE_COMBO == $passType) {

            $reserveInfo = $passReserveInfo;

            $fee = $reserveInfo['price'];
            $extraInfo = json_encode($reserveInfo);
            $type = $passType;
          }
        }



        $transaction = Transaction::create([
            'out_trade_no' => (function () {
                list($usec, $sec) = explode(" ", microtime());
                $usec = substr(str_replace('0.', '', $usec), 0 ,4);
                $str  = rand(10,99);
                return date("YmdHis").$usec.$str;
            })(),
            'fee' => $fee,
            'status' => 1,
            'user_id' => $user->id,
            'type' => $type,
            'extra_info' => $extraInfo,
        ]);

        $config = [
            'app_id'             => $appId,
            'mch_id'             => $payMerchantId,
            'key'                => $payApiKey,
            'cert_path'          => $certFile,
            'key_path'           => $keyFile,
            'notify_url'         => '',
            'sandbox' => false,
        ];

        $app = Factory::payment($config);

        $userThird = Third::where('user_id', $user->id)->find();

        $totalFee = $transaction->fee * 100;
        // 测试
        if ($testPay) {
            $totalFee = 1;
        }

        $result = $app->order->unify([
            'body' => $user->username . '用户充值的定单',
            'out_trade_no' => $transaction->out_trade_no,
            'total_fee' => $totalFee,
            'trade_type' => 'JSAPI', //微信支付的类型
            'openid' => $userThird->openid,  // @todo  确认怎么处理openid
            'notify_url' => url('/api/payment/notice', [], false, true)
        ]);

        $jssdk = $app->jssdk;
        $prepayId = $result['prepay_id'];
        $config = $jssdk->bridgeConfig($prepayId, false);
        $this->success('成功', $config);
    }

    public function notice()
    {
        $xml  = file_get_contents("php://input");
        libxml_disable_entity_loader(true);
        $array = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);

        Log::record($array, 'wxpay_notice');

        $outTradeNo = $array['out_trade_no'];

        $transaction = Transaction::where('out_trade_no', $outTradeNo)->find();
        //微信出现多次发起回调的问题, 已经支付成功，就停止后面的操作
        if (2 == $transaction->status) {
            echo '<xml>
  <return_code><![CDATA[SUCCESS]]></return_code>
  <return_msg><![CDATA[OK]]></return_msg>
</xml>';
            exit;
        }
        if (3 == $transaction->status or -1 == $transaction->status) {
            exit;
        }
        if ($array['return_code'] == 'SUCCESS' and $array['result_code'] == 'SUCCESS') {

            $transaction->status = 2;
            $transaction->transaction_no = $array['transaction_id'];
            // 需要先做更新防止因后面的执行错误导致不能存在支付编号
            $transaction->save();
            $userId = $transaction->user_id;

            if (Transaction::TRANS_TYPE_RECHARGE == $transaction->type) {
                $rechargeKey = $transaction->extra_info;
                $rechargeSetting = RechargeSetting::get($rechargeKey);

                $userExtend = Extend::where('user_id', $transaction->user_id)->find();

                $addNum = $rechargeSetting->num + $rechargeSetting->extra;
                $afterValue = $userExtend->balance + $addNum;

                Balance::create([
                    'user_id' => $transaction->user_id,
                    'type' => 1, //1=充值
                    'value' => $addNum,
                    'before_value' => $userExtend->balance,
                    'after_value' => $afterValue,
                    'transaction_id' => $transaction->id,
                    'createtime' => time(),
                    'updatetime' => time()
                ]);

                $userExtend->balance = $afterValue;
                $userExtend->save();

            } else if (Transaction::TRANS_TYPE_BUY_CARD == $transaction->type) {
                $cardId = $transaction->extra_info;

                $card = \app\common\model\Card::get($cardId);

                \app\admin\model\user\Card::create([
                    'user_id' => $transaction->user_id,
                    'card_id' => $card->id,
                    'name' => $card->card_name,
                    'type' => $card->card_type,
                    'price' => $card->card_price,
                    'service_start' => Carbon::now()->toDateTimeString(),
                    'service_end' => Carbon::now()->addDays($card->card_service_term_day)->toDateTimeString(),
                    'store_ids' => $card->store_ids,
//                    'checknum' => $card->card_checknum,
//                    'max_hour' => $card->card_max_hour,
                    'total_hour' => $card->card_total_hour,
                    'pay_way' => 2, //直接支付
                    'transaction_id' => $transaction->id,
                    'createtime' => time(),
                    'updatetime' => time()
                ]);

            } else if (Transaction::TRANS_TYPE_DIRECT_BUY == $transaction->type || Transaction::TRANS_TYPE_COMBO == $transaction->type) {
                $reserveInfo = json_decode($transaction->extra_info, true);

                $reserve = \app\admin\model\Reserve::get($reserveInfo['reserve_id']);

                $roomId = $reserveInfo['room_id'];
                $userCouponId = (isset($reserveInfo['couponid']) and is_numeric($reserveInfo['couponid']) and $reserveInfo['couponid'] > 0) ? $reserveInfo['couponid'] : null;
                // 组合的余额支付
                $balance = isset($reserveInfo['balance']) ? $reserveInfo['balance'] : 0;
                // 组合的卡券支付
                $cardId = isset($reserveInfo['card_id']) ? $reserveInfo['card_id'] : 0;
                $consumeHour = isset($reserveInfo['consume_hour']) ? $reserveInfo['consume_hour'] : 0;

                $roomInfo = model('room')->with('store')->find($roomId);

                //生成开门的密码
                $startTime = Carbon::parse($reserve->starttime);
                $endTime = Carbon::parse($reserve->endtime);
                if ($endTime->minute == 29 || $endTime->minute == 59) {
                    $endTime->addMinute();
                }

                $yunding = new Yunding();
//                $phoneNumber = $roomInfo->store->store_mobile ?? Env::get('common.mobile');
//                $password = $yunding->addPassword($roomInfo->yunding_homeid, $roomInfo->yunding_uuid, $phoneNumber, $startTime, $endTime);

                // 进行支付
                $payLib = new PayLib($userId, $reserve->id);
                Db::startTrans();

                try {
                    // 余额支付的参数
                    $balancePayData = [];
                    // 卡券支付的参数
                    $cardPayData = [];
                    // 如果有余额支付
                    if (!empty($balance)) {
                        $userExtend = Extend::where('user_id', $userId)->find();
                        $balanceId = $payLib->balancePay($balance, $userExtend);
                        if (empty($balanceId)) {
                            throw new \Exception('余额扣除失败');
                        }
                        $balancePayData = [
                            'pay_way' => 2,
                            'field_name' => 'balance_id',
                            'field_val' => $balanceId,
                        ];
                    }
                    // 如果是卡券支付
                    if (!empty($cardId) && !empty($consumeHour)) {
                        $payLib->cardPay($cardId, $consumeHour);
                        $cardPayData = [
                            'pay_way' => 1,
                            'field_name' => 'card_id',
                            'field_val' => $cardId,
                        ];
                    }

                    // 如果有优惠券
                    $payLib->couponPay($userCouponId);

                    $reserveLib = new ReserveLib(0, 0);
                    // 单纯的微信支付
                    $payData = [
                        'pay_way' => 3,
                        'field_name' => 'transaction_id',
                        'field_val' => $transaction->id,
                    ];
                    $fee = $transaction->fee;
                    // 如果组合支付是卡券支付
                    if (!empty($balancePayData)) {
                        $payData = [$balancePayData, $payData];
                        $fee = 0;
                    }
                    if (!empty($cardPayData)) {
                        $payData = [$cardPayData, $payData];
                        $fee = 0;
                    }

                    $res = [];
                    // 生成密码
                    if ($roomInfo->tts_lockid) {
                        $tts = new Tongtongsuo();
                        $user = \app\admin\model\User::get($userId);
                        // 增加10分钟
                        $endTime->addMinutes(20);
                        $res = $tts->addPassword($roomInfo->tts_lockid, $user->mobile, $startTime->toDateTimeString(), $endTime->toDateTimeString(), $user);
                        // 减掉10分钟
                        $endTime->subMinutes(20);
                    }
                    $reserveLib->updateReserve($reserve, $payData, $res, $userCouponId, $fee);

                    //当下时间就是下预约的时间，马上通电
                    //    因为crontab电源巡逻是5， 15， 25， 为了避免用户是在预约前5分钟下单，就没有电了
                    if (Carbon::now()->betweenIncluded($startTime->subMinutes(6), $endTime)) {
                        $yunding->elemeterSwitchOn($roomInfo->yunding_homeid, $roomInfo->yunding_elemetor_uuid);
                    }
                    Db::commit();
                } catch (\Exception $e) {
                    Db::rollback();
                    Log::write('支付回调出错 =>' . $e->getMessage());
                }

            } else if (Transaction::TRANS_TYPE_PUNISH == $transaction->type) {
                // 取消时的罚款
                $reserveInfo = json_decode($transaction->extra_info, true);

                $reserve = \app\admin\model\Reserve::get($reserveInfo['reserve_id']);
                $declineCredit = !empty($reserveInfo['decline_credit']) ? $reserveInfo['decline_credit'] : 0;
                $punishPrice = !empty($reserveInfo['price']) ? $reserveInfo['price'] : 0;
                $price = $transaction->fee;
                $reserveLib = new ReserveLib(0, 0);

                $code = (new CreditLib())->declineCredit($userId, $declineCredit);
                if ($code === 1) {
                    Log::write('支付回调出错 => 信用分扣除失败');
                } else {
                    $ret = $reserveLib->cancelReserve($userId, $reserve);
                }

            }
        } else {
            $transaction->status = -1;
            $transaction->save();
        }


        echo '<xml>
  <return_code><![CDATA[SUCCESS]]></return_code>
  <return_msg><![CDATA[OK]]></return_msg>
</xml>';
        exit;

    }
}


